/*
	This file is part of Floculate.
	Copyright (C) 2008  Bill Whitacre

	Floculate is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Floculate is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "system.h"

#include <windows.h>
#include <GL/gl.h>

/* Data structure for holding the Win32 video context with GL. */
typedef struct GLWindow
{
	int _is_registered;
	int get_started;

    HWND hwnd;                                  /* Window object handle. */
    HDC hdc;                                    /* Device context handle. */
	HGLRC glrc;                                 /* WGL rendering context.*/

	unsigned int width,height;
    unsigned int depth,fs;
    
    rat_key_map *keymap;
    
    char name[2048];
    
    int resizedevent;
    int apptermevent;
    
    float mousex,mousey;
    char buttons[8];
    char keys[256];
} GLWindow;

#define RAT_WINDOW_CLASS "RAT_WINDOW_CLASS"
/* Flag stating whether or not our window class is registered. */

GLWindow GLWin; /* Pointer for the main context. */

LRESULT CALLBACK rat_hwnd_proc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp);

/* Create a keymap for win32 vkeys. */
static void gen_w32_keymap(rat_key_map *keymap)
{
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_LBUTTON,RAT_KEY_LBUTTON));
	rat_key_map_add_pair(keymap,rat_key_pair_create(VK_RBUTTON,RAT_KEY_RBUTTON));
	rat_key_map_add_pair(keymap,rat_key_pair_create(VK_CANCEL,RAT_KEY_CANCEL)); // ???
	rat_key_map_add_pair(keymap,rat_key_pair_create(VK_MBUTTON,RAT_KEY_MBUTTON));
#ifdef _MSC_VER
	rat_key_map_add_pair(keymap,rat_key_pair_create(VK_XBUTTON1,RAT_KEY_XBUTTON1));
	rat_key_map_add_pair(keymap,rat_key_pair_create(VK_XBUTTON2,RAT_KEY_XBUTTON2));
#endif
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_BACK,RAT_KEY_BACK));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_TAB,RAT_KEY_TAB));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_CLEAR,RAT_KEY_CLEAR));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_RETURN,RAT_KEY_RETURN));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SHIFT,RAT_KEY_SHIFT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_CONTROL,RAT_KEY_CONTROL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_MENU,RAT_KEY_MENU));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_PAUSE,RAT_KEY_PAUSE));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_CAPITAL,RAT_KEY_CAPITAL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_KANA,RAT_KEY_KANA));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_HANGEUL,RAT_KEY_HANGUEL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_HANGUL,RAT_KEY_HANGUL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_JUNJA,RAT_KEY_JUNJA));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_FINAL,RAT_KEY_FINAL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_HANJA,RAT_KEY_HANJA));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_KANJI,RAT_KEY_KANJI));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_ESCAPE,RAT_KEY_ESCAPE));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_CONVERT,RAT_KEY_CONVERT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NONCONVERT,RAT_KEY_NONCONVERT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_ACCEPT,RAT_KEY_ACCEPT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_MODECHANGE,RAT_KEY_MODECHANGE));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SPACE,RAT_KEY_SPACE));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_PRIOR,RAT_KEY_PRIOR));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NEXT,RAT_KEY_NEXT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_END,RAT_KEY_END));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_HOME,RAT_KEY_HOME));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_LEFT,RAT_KEY_LEFT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_UP,RAT_KEY_UP));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_RIGHT,RAT_KEY_RIGHT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_DOWN,RAT_KEY_DOWN));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SELECT,RAT_KEY_SELECT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_PRINT,RAT_KEY_PRINT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_EXECUTE,RAT_KEY_EXECUT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SNAPSHOT,RAT_KEY_SNAPSHOT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_INSERT,RAT_KEY_INSERT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_DELETE,RAT_KEY_DELETE));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_HELP,RAT_KEY_HELP));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_LWIN,RAT_KEY_LSUPER));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_RWIN,RAT_KEY_RSUPER));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_APPS,RAT_KEY_APPS));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SLEEP,RAT_KEY_SLEEP));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD0,RAT_KEY_NUMPAD0));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD1,RAT_KEY_NUMPAD1));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD2,RAT_KEY_NUMPAD2));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD3,RAT_KEY_NUMPAD3));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD4,RAT_KEY_NUMPAD4));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD5,RAT_KEY_NUMPAD5));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD6,RAT_KEY_NUMPAD6));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD7,RAT_KEY_NUMPAD7));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD8,RAT_KEY_NUMPAD8));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMPAD9,RAT_KEY_NUMPAD9));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_MULTIPLY,RAT_KEY_MULTIPLY));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_ADD,RAT_KEY_ADD));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SEPARATOR,RAT_KEY_SEPARATOR));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SUBTRACT,RAT_KEY_SUBTRACT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_DECIMAL,RAT_KEY_DECIMAL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_DIVIDE,RAT_KEY_DIVIDE));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F1,RAT_KEY_F1));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F2,RAT_KEY_F2));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F3,RAT_KEY_F3));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F4,RAT_KEY_F4));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F5,RAT_KEY_F5));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F6,RAT_KEY_F6));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F7,RAT_KEY_F7));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F8,RAT_KEY_F8));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F9,RAT_KEY_F9));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F10,RAT_KEY_F10));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F11,RAT_KEY_F11));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F12,RAT_KEY_F12));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F13,RAT_KEY_F13));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F14,RAT_KEY_F14));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F15,RAT_KEY_F15));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F16,RAT_KEY_F16));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F17,RAT_KEY_F17));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F18,RAT_KEY_F18));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F19,RAT_KEY_F19));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F20,RAT_KEY_F20));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F21,RAT_KEY_F21));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F22,RAT_KEY_F22));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F23,RAT_KEY_F23));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_F24,RAT_KEY_F24));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NUMLOCK,RAT_KEY_NUMLOCK));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_SCROLL,RAT_KEY_SCROLL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_LSHIFT,RAT_KEY_LSHIFT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_RSHIFT,RAT_KEY_RSHIFT));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_LCONTROL,RAT_KEY_LCONTROL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_RCONTROL,RAT_KEY_RCONTROL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_LMENU,RAT_KEY_LMENU));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_RMENU,RAT_KEY_RMENU));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_ATTN,RAT_KEY_ATTN));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_CRSEL,RAT_KEY_CRSEL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_EXSEL,RAT_KEY_EXSEL));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_EREOF,RAT_KEY_EREOF));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_PLAY,RAT_KEY_PLAY));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_ZOOM,RAT_KEY_ZOOM));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_NONAME,0));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_PA1,RAT_KEY_PA1));
    rat_key_map_add_pair(keymap,rat_key_pair_create(VK_OEM_CLEAR,RAT_KEY_OEM_CLEAR));
    rat_key_map_sort(keymap);
}

LRESULT CALLBACK rat_hwnd_proc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
    int btnnum=-1;

    PAINTSTRUCT ps;
    rat_key_map *keymap;
    RAT_KEY_CODE ratkey;
    WPARAM vkey;

    /* Welcome to hell - Windows message proccessing. */
    if (!GLWin.get_started) return DefWindowProc(hwnd,msg,wp,lp);

	switch (msg) /* Handle messages. */
    {
    case WM_CREATE:
        ShowWindow(hwnd,SW_SHOW);
        return 0;
        break;
    case WM_DESTROY:
        /* Destroy context.  First release the device context. */
        ReleaseDC(hwnd,GLWin.hdc);
        if (GLWin.fs) /* If in fullscreen... */
        {
            /* Restore the device mode. */
            if (ChangeDisplaySettings(NULL,0)!=DISP_CHANGE_SUCCESSFUL)
            {
                printf("Device mode restore failed!  WIN32ERROR==0x%08x",GetLastError());
                return 0;
            }
            GLWin.fs=0; /* No longer in full screen. */
        }
        return 0;
    case WM_QUIT:
    case WM_CLOSE:
        GLWin.apptermevent=1; /* Quit/Close message received, set app terminate.  We're going down. */
        return 0;
    case WM_SIZE:
        GLWin.height=HIWORD(lp);
        GLWin.width=LOWORD(lp);
        GLWin.resizedevent=1;

        ReleaseDC(GLWin.hwnd,GLWin.hdc);
        GLWin.hdc=GetDC(GLWin.hwnd);

        return 0;
    case WM_ERASEBKGND: return 0;
    case WM_PAINT:
        /* No painting. */
        BeginPaint(hwnd,&ps);
        EndPaint(hwnd,&ps);

        return 0;
    case WM_ACTIVATEAPP:
        return 0;
    case WM_KEYDOWN:
        vkey=wp;
        ratkey=rat_key_map_get_code(GLWin.keymap,vkey);

        if (ratkey)
            GLWin.keys[ratkey]=1;
        else
            GLWin.keys[vkey]=1;

        return 0;
    case WM_KEYUP:
        vkey=wp;
        ratkey=rat_key_map_get_code(GLWin.keymap,vkey);

        if (ratkey)
            GLWin.keys[ratkey]=0;
        else
            GLWin.keys[vkey]=0;

        return 0;
    case WM_RBUTTONDOWN: btnnum++; /* Right mouse button pressed */
    case WM_MBUTTONDOWN: btnnum++; /* Middle mouse button pressed */
    case WM_LBUTTONDOWN: btnnum++; /* Left mouse button pressed */
        GLWin.buttons[btnnum]=1;
        return 0;
    case WM_RBUTTONUP: btnnum++; /* Right mouse button released */
    case WM_MBUTTONUP: btnnum++; /* Middle mouse button released */
    case WM_LBUTTONUP: btnnum++; /* Left mouse button released */
        GLWin.buttons[btnnum]=0;
        return 0;
    case WM_MOUSEMOVE:
        GLWin.mousex=(double)LOWORD(lp)/(double)GLWin.width;
        GLWin.mousey=(double)HIWORD(lp)/(double)GLWin.height;
        return 0;
    case WM_SYSCOMMAND:
        /* System call made. */
        if (wp==SC_SCREENSAVE||wp==SC_MONITORPOWER) return 0;
        break;
    default:
        break;
    }

    return DefWindowProc(hwnd,msg,wp,lp); /* Default window proc. */
}

static int get_pfd_object(int bpp,PIXELFORMATDESCRIPTOR *pfd)
{
	memset(pfd,0,sizeof(PIXELFORMATDESCRIPTOR));
    pfd->nSize=sizeof(PIXELFORMATDESCRIPTOR);
    pfd->nVersion=1;
    pfd->dwFlags=PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER;
    switch (bpp)
    {
    case 32:
		pfd->iPixelType=PFD_TYPE_RGBA;
		pfd->cColorBits=32;
		pfd->cAlphaBits=32;
		pfd->cDepthBits=32;
		pfd->cStencilBits=1;
		break;
	case 16:
		pfd->iPixelType=PFD_TYPE_RGBA;
        pfd->cRedBits=5;
        pfd->cGreenBits=6;
        pfd->cBlueBits=5;
		pfd->cDepthBits=16;
		pfd->cStencilBits=1;
		break;
    default: /* No match. */
        return 0; /* Failiure. */
    }
    pfd->dwDamageMask=0;
    pfd->iLayerType=PFD_MAIN_PLANE;

    return 1; /* Success! */
}

int rat_start_system_core(char *name,unsigned int vw,
	unsigned int vh,unsigned int vbpp,int vfs)
{
	WNDCLASSEX wc;
    DWORD dwExStyle;       // Window Extended Style
    DWORD dwStyle;         // Window Style
    RECT windowRect;
	PIXELFORMATDESCRIPTOR pfd;
	int pfmt;

	memset(&GLWin,0,sizeof(GLWindow));
    strcpy(GLWin.name,name);

	printf("Registering application class...");

	wc.cbSize=sizeof(WNDCLASSEX);
	/* Video "style."  We take control of H/V redraw as well as claiming full ownership. */
	wc.style=CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
	wc.lpfnWndProc=rat_hwnd_proc;
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
	wc.hInstance=GetModuleHandle(NULL);
	wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wc.hCursor=LoadCursor(NULL,IDC_ARROW);
	wc.hbrBackground=NULL;
	wc.lpszMenuName=NULL;
	wc.lpszClassName=RAT_WINDOW_CLASS;
	wc.hIconSm=NULL;

	/* Register that puppy. */
	GLWin._is_registered=RegisterClassEx(&wc);
	if (!GLWin._is_registered)
	{
		printf("FAILED.\n");
		return 0;
	}
	else
		printf("DONE!\n");

	GLWin.keymap=rat_key_map_create();
    gen_w32_keymap(GLWin.keymap);

	if (vfs)                             // vfs?
    {
		printf("Fullscreen requested.  Switching...");
        DEVMODE dmScreenSettings;                   // device mode
        memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
        dmScreenSettings.dmSize = sizeof(dmScreenSettings); 
        dmScreenSettings.dmPelsWidth = vw;         // screen width
        dmScreenSettings.dmPelsHeight = vh;           // screen height
        dmScreenSettings.dmBitsPerPel = vbpp;             // bits per pixel
        dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

        if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
        {
            // setting display mode failed, switch to windowed
			printf("FAILED.\n");
            vfs=0;
        }
		else
			printf("DONE!\n");
    }

    if (vfs)                             // Are We Still In Fullscreen Mode?
    {
        dwExStyle=WS_EX_APPWINDOW;                  // Window Extended Style
        dwStyle=WS_POPUP;                       // Windows Style
    }
    else
    {
        dwExStyle=WS_EX_APPWINDOW|WS_EX_WINDOWEDGE;   // Window Extended Style
        dwStyle=WS_OVERLAPPEDWINDOW;                    // Windows Style
    }

	GLWin.fs=vfs;
	GLWin.width=vw;
	GLWin.height=vh;
	GLWin.depth=vbpp;

	windowRect.left=windowRect.top=0;
	windowRect.right=vw;
	windowRect.bottom=vh;

    AdjustWindowRectEx(&windowRect,dwStyle,FALSE,dwExStyle);     // Adjust Window To True Requested Size

	printf("Creating window...");

    // class registered, so now create our window
    GLWin.hwnd = CreateWindowEx(dwExStyle,                                 // extended style
        RAT_WINDOW_CLASS,                          // class name
        name,      // app name
        dwStyle|WS_CLIPCHILDREN|
        WS_CLIPSIBLINGS,
        0,0,                               // x,y coordinate
        windowRect.right-windowRect.left,
        windowRect.bottom-windowRect.top, // width, height
        (void *)0,                               // handle to parent
        (void *)0,                               // handle to menu
        GetModuleHandle(NULL),           // application instance
        (void *)0);                              // no extra params

    // check if window creation failed (hwnd would equal NULL)
    if (!GLWin.hwnd)
	{
		printf("FAILED.\n");
		return 0;
	}
	printf("DONE!\n");

    ShowWindow(GLWin.hwnd,SW_SHOW);          // display the window
    UpdateWindow(GLWin.hwnd);                 // update the window

	GLWin.hdc=GetDC(GLWin.hwnd);
    if (!GLWin.hdc)
    {
        printf("Getting device context failed!  WIN32ERROR==0x%08x",GetLastError());
        return 0; /* Failiure. */
    }
    printf("Obtained device context.\n");

    if (!get_pfd_object(vbpp,&pfd)) return 0; /* Failiure. */

    /* Select a pixel format. */
    pfmt=ChoosePixelFormat(GLWin.hdc,&pfd);
    if (!pfmt)
    {
        printf("Selected pixel format failed!  WIN32ERROR==0x%08x",GetLastError());
        return 0; /* Failiure. */
    }
    printf("Selected pixel format.\n");

    /* Realize our selected pixel format. */
    if (!SetPixelFormat(GLWin.hdc,pfmt,&pfd))
    {
        printf("Pixel format could not be realized!  WIN32ERROR==0x%08x",GetLastError());
        return 0; /* Failiure. */
    }
    printf("Realized pixel format.\n");

    /* Create a WGL rendering context. */
    GLWin.glrc=wglCreateContext(GLWin.hdc);
    if (!GLWin.glrc)
    {
        printf("Failed to create WGL context!  WIN32ERROR==0x%08x",GetLastError());
        return 0; /* Failiure. */
    }
    printf("Created WGL context.\n");

    /* Make sure this context is our current rendering context. */
    if (!wglMakeCurrent(GLWin.hdc,GLWin.glrc))
    {
        printf("Failed to attach WGL context.  WIN32ERROR==0x%08x",GetLastError());
        return 0; /* Failiure. */
    }
    printf("Attached WGL context.\nCan't tell if there's direct rendering because Win32 does not\nhave a mechanism for handling that.\nThe window is good to go.\n");

	GLWin.get_started=1;

	return 1;
}

void rat_stop_system_core()
{
	/* Release the current context. */
    wglMakeCurrent(GLWin.hdc,NULL);
    printf("Released rendering context.\n");

    /* Delete our context. */
    wglDeleteContext(GLWin.glrc);
    printf("Deleted rendering context.\n");

	DestroyWindow(GLWin.hwnd);
    printf("Destroyed window.\n");

    /* Free memory. */
    rat_key_map_destroy(GLWin.keymap);

	UnregisterClass(RAT_WINDOW_CLASS,GetModuleHandle(NULL));
}

void rat_video_size(unsigned int *vw,unsigned int *vh)
{
	*vw=GLWin.width;
	*vh=GLWin.height;
}

int rat_handle_events()
{
	MSG msg;

    /* Go through all messages. */
	if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
	{
		TranslateMessage(&msg); /* Translate message in to usable form. */
		DispatchMessage(&msg);  /* Dispatch the message to our callback. */
	}

	return 1; /* Success! */
}

int rat_update_video()
{
	/* Try swapping the buffers. */
    if (!SwapBuffers(GLWin.hdc))
    {
        /* If we failed it may because we lost the device context. */
        GLWin.hdc=GetDC(GLWin.hwnd);
        return SwapBuffers(GLWin.hdc); /* Tries to swap buffers and returns success. */
    }

	return 1;
}

void rat_get_mouse_position(float *x,float *y)
{
	*x=GLWin.mousex;
	*y=GLWin.mousey;
}

int rat_is_key_down(RAT_KEY_CODE key)
{
	return GLWin.keys[key];
}

int rat_is_mouse_down(int button)
{
	return GLWin.buttons[button];
}

int rat_appterm_event()
{
	return GLWin.apptermevent;
}

int rat_resized_event()
{
	return GLWin.resizedevent;
}
